home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / Src / Ch16 / SolidPho.cls < prev   
Text File  |  1999-06-29  |  10KB  |  378 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "Solid3d"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = False
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15.  
  16. ' These Face3d objects are the oriented faces.
  17. Public Faces As Collection
  18.  
  19. Public zmax As Single
  20.  
  21. Public IsConvex As Boolean
  22. Public HideSurfaces As Boolean
  23. ' Return the transformed bounds.
  24. Public Sub GetRminRmax(ByRef Rmin As Single, ByRef Rmax As Single, ByVal light_x As Single, ByVal light_y As Single, ByVal light_z As Single)
  25. Dim face As Face3d
  26. Dim dx As Single
  27. Dim dy As Single
  28. Dim dz As Single
  29. Dim new_rmin As Single
  30. Dim new_rmax As Single
  31.  
  32.     Rmin = 1E+30
  33.     Rmax = -1E+30
  34.  
  35.     For Each face In Faces
  36.         face.GetRminRmax new_rmin, new_rmax, _
  37.             light_x, light_y, light_z
  38.  
  39.         If Rmin > new_rmin Then Rmin = new_rmin
  40.         If Rmax < new_rmax Then Rmax = new_rmax
  41.     Next face
  42. End Sub
  43. ' Set the diffuse reflection coefficients for
  44. ' the faces.
  45. Public Sub SetDiffuseCoefficients(ByVal kr As Single, ByVal kg As Single, ByVal kb As Single)
  46. Dim face As Face3d
  47.  
  48.     For Each face In Faces
  49.         face.DiffuseKr = kr
  50.         face.DiffuseKg = kg
  51.         face.DiffuseKb = kb
  52.     Next face
  53. End Sub
  54. ' Set the ambient coefficients for the faces.
  55. Public Sub SetAmbientCoefficients(ByVal kr As Single, ByVal kg As Single, ByVal kb As Single)
  56. Dim face As Face3d
  57.  
  58.     For Each face In Faces
  59.         face.AmbientKr = kr
  60.         face.AmbientKg = kg
  61.         face.AmbientKb = kb
  62.     Next face
  63. End Sub
  64. ' Set the Specular coefficients for the faces.
  65. Public Sub SetSpecularCoefficients(ByVal k As Single, ByVal n As Integer)
  66. Dim face As Face3d
  67.  
  68.     For Each face In Faces
  69.         face.SpecularK = k
  70.         face.SpecularN = n
  71.     Next face
  72. End Sub
  73.  
  74.  
  75. ' Sort the faces so those with the largest
  76. ' transformed Z coordinates come first.
  77. '
  78. ' As we switch faces around, we keep track of the
  79. ' number of switches we have made. If it clear we
  80. ' are stuck in an infinite loop, just move the
  81. ' first face to the ordered_faces collection so we
  82. ' can continue.
  83. Public Sub SortFaces()
  84. Dim ordered_faces As Collection
  85. Dim face_1 As Face3d
  86. Dim face_i As Face3d
  87. Dim i As Integer
  88. Dim xmin As Single
  89. Dim xmax As Single
  90. Dim ymin As Single
  91. Dim ymax As Single
  92. Dim zmin As Single
  93. Dim zmax As Single
  94. Dim xmini As Single
  95. Dim xmaxi As Single
  96. Dim ymini As Single
  97. Dim ymaxi As Single
  98. Dim zmini As Single
  99. Dim zmaxi As Single
  100. Dim overlap As Boolean
  101. Dim switches As Integer
  102. Dim max_switches As Integer
  103.  
  104.     Set ordered_faces = New Collection
  105.  
  106.     ' Pull out any that are culled. These are not
  107.     ' drawn so we can put them at the front of
  108.     ' the ordered_faces collection.
  109.     For i = Faces.Count To 1 Step -1
  110.         If Faces(i).IsCulled Then
  111.             ordered_faces.Add Faces(i)
  112.             Faces.Remove i
  113.         End If
  114.     Next i
  115.  
  116.     ' Order the remaining faces.
  117.     max_switches = Faces.Count
  118.     Do While Faces.Count > 0
  119.         ' Get the first item's extent.
  120.         Set face_1 = Faces(1)
  121.         face_1.GetExtent xmin, xmax, ymin, ymax, zmin, zmax
  122.  
  123.         ' Compare this face to the others.
  124.         overlap = False     ' In case Face.Count = 0.
  125.         For i = 2 To Faces.Count
  126.             Set face_i = Faces(i)
  127.  
  128.             ' Get item i's extent.
  129.             face_i.GetExtent xmini, xmaxi, ymini, ymaxi, zmini, zmaxi
  130.             overlap = True
  131.             If xmaxi <= xmin Or xmini >= xmax Or _
  132.                ymaxi <= ymin Or ymini >= ymax Or _
  133.                zmini >= zmax _
  134.             Then
  135.                 ' The extents do not overlap.
  136.                 overlap = False
  137.             ElseIf face_i.IsAbove(face_1) Then
  138.                 ' Face i is all above the plane
  139.                 ' of face 1.
  140.                 overlap = False
  141.             ElseIf face_1.IsBelow(face_i) Then
  142.                 ' Face 1 is all beneath the plane
  143.                 ' of face i.
  144.                 overlap = False
  145.             ElseIf Not face_1.Obscures(face_i) Then
  146.                 ' If face_1 does not lie partly above
  147.                 ' face_i, then there is no problem.
  148.                 overlap = False
  149.             End If
  150.  
  151.             If overlap Then Exit For
  152.         Next i
  153.  
  154.         If overlap And switches < max_switches Then
  155.             ' There's overlap, move face i to the
  156.             ' top of the list.
  157.             Faces.Remove i
  158.             Faces.Add face_i, , 1 ' Before position 1.
  159.             switches = switches + 1
  160.         Else
  161.             ' There's no overlap. Move face 1 to
  162.             ' the ordered_faces collection.
  163.             ordered_faces.Add face_1
  164.             Faces.Remove 1
  165.             max_switches = Faces.Count
  166.             switches = 0
  167.         End If
  168.     Loop ' Loop until we've ordered all the faces.
  169.  
  170.     ' Replace the Faces collection with the
  171.     ' ordered_faces collection.
  172.     Set Faces = ordered_faces
  173. End Sub
  174. ' Set the ZMax value for the solid.
  175. Public Sub SetZmax()
  176. Dim face As Face3d
  177. Dim z_max As Single
  178.  
  179.     zmax = -1E+30
  180.  
  181.     For Each face In Faces
  182.         z_max = face.zmax()
  183.         If zmax < z_max Then zmax = z_max
  184.     Next face
  185. End Sub
  186. ' Create a pyramid with height L and base given
  187. ' by the points in the coord array. Add the
  188. ' faces that make up the pyramid to this solid.
  189. Public Sub Stellate(L As Single, ParamArray coord() As Variant)
  190. Dim x0 As Single
  191. Dim y0 As Single
  192. Dim z0 As Single
  193. Dim x1 As Single
  194. Dim y1 As Single
  195. Dim z1 As Single
  196. Dim x2 As Single
  197. Dim y2 As Single
  198. Dim z2 As Single
  199. Dim x3 As Single
  200. Dim y3 As Single
  201. Dim z3 As Single
  202. Dim Ax As Single
  203. Dim Ay As Single
  204. Dim Az As Single
  205. Dim Bx As Single
  206. Dim By As Single
  207. Dim Bz As Single
  208. Dim Nx As Single
  209. Dim Ny As Single
  210. Dim Nz As Single
  211. Dim num As Integer
  212. Dim i As Integer
  213. Dim pt As Integer
  214.  
  215.     num = (UBound(coord) + 1) \ 3
  216.     If num < 3 Then
  217.         MsgBox "Must have at least 3 points to stellate.", , vbExclamation
  218.         Exit Sub
  219.     End If
  220.  
  221.     ' (x0, y0, z0) is the center of the polygon.
  222.     x0 = 0
  223.     y0 = 0
  224.     z0 = 0
  225.     pt = 0
  226.     For i = 1 To num
  227.         x0 = x0 + coord(pt)
  228.         y0 = y0 + coord(pt + 1)
  229.         z0 = z0 + coord(pt + 2)
  230.         pt = pt + 3
  231.     Next i
  232.     x0 = x0 / num
  233.     y0 = y0 / num
  234.     z0 = z0 / num
  235.  
  236.     ' Find the normal.
  237.     x1 = coord(0)
  238.     y1 = coord(1)
  239.     z1 = coord(2)
  240.     x2 = coord(3)
  241.     y2 = coord(4)
  242.     z2 = coord(5)
  243.     x3 = coord(6)
  244.     y3 = coord(7)
  245.     z3 = coord(8)
  246.     Ax = x2 - x1
  247.     Ay = y2 - y1
  248.     Az = z2 - z1
  249.     Bx = x3 - x2
  250.     By = y3 - y2
  251.     Bz = z3 - z2
  252.     m3Cross Nx, Ny, Nz, Ax, Ay, Az, Bx, By, Bz
  253.  
  254.     ' Give the normal length L.
  255.     m3SizeVector L, Nx, Ny, Nz
  256.  
  257.     ' The normal + <x0, y0, z0> gives the point.
  258.     x0 = x0 + Nx
  259.     y0 = y0 + Ny
  260.     z0 = z0 + Nz
  261.  
  262.     ' Build the faces.
  263.     x1 = coord(3 * num - 3)
  264.     y1 = coord(3 * num - 2)
  265.     z1 = coord(3 * num - 1)
  266.     pt = 0
  267.     For i = 1 To num
  268.         x2 = coord(pt)
  269.         y2 = coord(pt + 1)
  270.         z2 = coord(pt + 2)
  271.         AddFace x1, y1, z1, x2, y2, z2, x0, y0, z0
  272.         x1 = x2
  273.         y1 = y2
  274.         z1 = z2
  275.         pt = pt + 3
  276.     Next i
  277. End Sub
  278.  
  279.  
  280. ' Clip faces.
  281. Public Sub ClipEye(ByVal R As Single)
  282. Dim obj As Face3d
  283.  
  284.     For Each obj In Faces
  285.         obj.ClipEye R
  286.     Next obj
  287. End Sub
  288.  
  289. ' Add an oriented face to the solid.
  290. Public Sub AddFace(ParamArray coord() As Variant)
  291. Dim face As Face3d
  292. Dim num As Integer
  293. Dim pt As Integer
  294. Dim i As Integer
  295.  
  296.     num = (UBound(coord) + 1) \ 6
  297.     If num < 3 Then
  298.         MsgBox "Faces in a Solid must contain at least 3 points.", , vbExclamation
  299.         Exit Sub
  300.     End If
  301.  
  302.     Set face = New Face3d
  303.     Faces.Add face
  304.  
  305.     ' Add the vertex coordinates.
  306.     pt = 0
  307.     For i = 1 To num
  308.         face.AddPoints (coord(pt)), (coord(pt + 1)), (coord(pt + 2))
  309.         pt = pt + 3
  310.     Next i
  311.  
  312.     ' Add the vertex normals.
  313.     pt = 0
  314.     For i = 1 To num
  315.         face.AddNormals (coord(pt)), (coord(pt + 1)), (coord(pt + 2))
  316.         pt = pt + 3
  317.     Next i
  318. End Sub
  319. ' Perform backface removal on the faces for
  320. ' center of projection at (X, Y, Z).
  321. Public Sub Cull(ByVal X As Single, ByVal Y As Single, ByVal Z As Single)
  322. Dim obj As Face3d
  323.  
  324.     For Each obj In Faces
  325.         obj.Cull X, Y, Z
  326.     Next obj
  327. End Sub
  328. ' Set or clear the Culled property for all faces.
  329. Property Let Culled(ByVal new_value As Boolean)
  330. Dim obj As Face3d
  331.  
  332.     For Each obj In Faces
  333.         obj.IsCulled = new_value
  334.     Next obj
  335. End Property
  336.  
  337.  
  338.  
  339. ' Apply a transformation matrix which may not
  340. ' contain 0, 0, 0, 1 in the last column to the
  341. ' object.
  342. Public Sub ApplyFull(M() As Single)
  343. Dim obj As Face3d
  344.  
  345.     For Each obj In Faces
  346.         obj.ApplyFull M
  347.     Next obj
  348. End Sub
  349.  
  350. ' Apply a transformation matrix to the object.
  351. Public Sub Apply(M() As Single)
  352. Dim obj As Face3d
  353.  
  354.     For Each obj In Faces
  355.         obj.Apply M
  356.     Next obj
  357. End Sub
  358.  
  359.  
  360. ' Draw the transformed solid on a PictureBox.
  361. Public Sub Draw(ByVal pic As PictureBox, ByVal light_sources As Collection, ByVal ambient_light As Integer, ByVal eye_x As Single, ByVal eye_y As Single, ByVal eye_z As Single)
  362. Dim face As Face3d
  363.  
  364.     ' If we do not know this is a convex solid,
  365.     ' order the faces.
  366.     If HideSurfaces And (Not IsConvex) Then SortFaces
  367.  
  368.     ' Draw the faces.
  369.     For Each face In Faces
  370.         face.Draw pic, light_sources, ambient_light, eye_x, eye_y, eye_z
  371.     Next face
  372. End Sub
  373. Private Sub Class_Initialize()
  374.     Set Faces = New Collection
  375. End Sub
  376.  
  377.  
  378.